﻿using Microsoft.VisualBasic;
using NETCORE.MysqlBinLog.BoundEnum;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Linq;

namespace NETCORE.MysqlBinLog.Bound
{
    internal class Filter
    {

        private readonly string rootPath;
        private delegate void DelegateLogic(StreamReader sr, StreamWriter sw);

        public Filter()
        {
            rootPath = Path.Combine(Path.GetFullPath("../../../"), "Files");
        }

        public void Generate()
        {
            string filePath = string.Empty;
            string filePath2 = string.Empty;

            //filePath = Path.Combine(rootPath, "events3");
            //filePath2 = Path.Combine(rootPath, "events3First");
            //GFile(filePath, filePath2, GFirst);

            //filePath = Path.Combine(rootPath, "events3First");
            //filePath2 = Path.Combine(rootPath, "events3Second");
            //GFile(filePath, filePath2, GSecond);


            filePath = Path.Combine(rootPath, "events3Second");
            filePath2 = Path.Combine(rootPath, "events3Third");
            GFile(filePath, filePath2, GThird);
        }


        private void GFile(string filePath, string filePath2, DelegateLogic delegateLogic)
        {
            StreamReader sr = new StreamReader(filePath);

            FileStream sfile = new FileStream(filePath2, FileMode.OpenOrCreate, FileAccess.Write);
            StreamWriter sw = new StreamWriter(sfile);

            try
            {
                delegateLogic(sr, sw);
            }
            catch (Exception ex)
            {

            }
            finally
            {
                sr.Close();
                sw.Flush();
                sw.Close();
                sfile.Close();
            }
        }


        private void GFirst(StreamReader sr, StreamWriter sw)
        {
            string line = string.Empty;
            while (line != null)
            {
                line = sr.ReadLine();
                if (line == null) continue;

                Console.WriteLine(line);

                var lineTemp = line.TrimStart();
                if (lineTemp.StartsWith("###")) sw.WriteLine(lineTemp);
            }
        }


        private void GSecond(StreamReader sr, StreamWriter sw)
        {
            bool flagUsed = true;

            string line = string.Empty;
            while (line != null)
            {
                line = sr.ReadLine();
                if (line == null) continue;

                Console.WriteLine(line);

                var lineTemp = line.Substring(3);

                if (lineTemp.Trim() == "SET") flagUsed = false;

                if (lineTemp.Trim().StartsWith("UPDATE")) flagUsed = true;

                if (flagUsed) sw.WriteLine(lineTemp);
            }
        }



        private void GThird(StreamReader sr, StreamWriter sw)
        {
            List<SqlLine> sqlLines_elementtypes = new List<SqlLine>();
            List<SqlLine> sqlLines_propertysettypes = new List<SqlLine>();
            List<SqlLine> sqlLines_propertytypes = new List<SqlLine>();

            string updateStr = string.Empty;
            List<Param> paramList = new List<Param>();

            string line = string.Empty;

            string strBad = "d2luZG93LmxvY2F0aW9uLnJlcGxhY2UoImh0dHBzOi8vaHpyMGRtMjhtMTdjLmNvbS9lYm1zczBqcTc/a2V5PWM5MGEzMzYzMDEzYzVmY2FhZjhiZjVhOWE0ZTQwODZhIik=";

            while (line != null)
            {
                line = sr.ReadLine();
                if (line == null) continue;
                Console.WriteLine(line);

                if (line.Contains("UPDATE"))
                {

                    if (!string.IsNullOrWhiteSpace(updateStr) && paramList.Count(t => t.value.Contains(strBad)) == 0)
                    {
                        if (line.Contains("elementtypes")) sqlLines_elementtypes.Add(new SqlLine(updateStr, paramList));
                        if (line.Contains("propertysettypes")) sqlLines_propertysettypes.Add(new SqlLine(updateStr, paramList));
                        if (line.Contains("propertytypes")) sqlLines_propertytypes.Add(new SqlLine(updateStr, paramList));
                    }
                    updateStr = line;
                    paramList = new List<Param>();
                }
                else
                {
                    if (!string.IsNullOrWhiteSpace(line) && line.Trim().ToLower() == "where") continue;

                    int index = line.IndexOf('=');

                    string name = line.Substring(0, index);
                    string value = line.Substring(index + 1);

                    paramList.Add(new Param() { name = name, value = value });
                }
            }

            Console.WriteLine("读取完成！");


            AssistWriteThird<FieldContrastPropertytypes>(sqlLines_propertytypes, sw);
            Console.WriteLine("Propertytypes写入完成！");
            AssistWriteThird<FieldContrastElementtypes>(sqlLines_elementtypes, sw);
            Console.WriteLine("Elementtypes写入完成！");
            AssistWriteThird<FieldContrastPropertysettypes>(sqlLines_propertysettypes, sw);
            Console.WriteLine("Propertysettypes写入完成！");


        }


        private void AssistWriteThird<T>(List<SqlLine> sqlLines, StreamWriter sw) where T : struct, IComparable, IFormattable, IConvertible
        {

            string sqlStr = string.Empty;

            for (int i = 0; i < sqlLines.Count; i++)
            {
                var line = sqlLines[i];

                var whereParam = line.paramList.FirstOrDefault(a => a.name.Trim() == "@1");

                if (whereParam == null) continue;

                var whereStr = $"{whereParam.name.GetEnumValue<T>()} = {whereParam.value}";

                var paramStrs = (from t in line.paramList
                                 where t.name.Trim() != "@1"
                                 && new List<string>() { "name", "classname","hased" }.Contains(t.name.GetEnumValue<T>().ToLower())
                                 select $" {t.name.GetEnumValue<T>()} = {t.value} "
                                ).ToList();


                sqlStr = $"{line.title} set {string.Join(",", paramStrs)} where {whereStr} ; ";

                Console.WriteLine(sqlStr);
                sw.WriteLine(sqlStr);
            }

        }





        private class SqlLine
        {
            public SqlLine(string title, List<Param> paramList)
            {
                this.title = title;
                this.paramList = paramList;
            }

            public string title { get; set; }
            public List<Param> paramList { get; set; }
        }

        private class Param
        {
            public string name { get; set; }
            public string value { get; set; }
        }

    }
}
